/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

// --------------------------------------------------------------------------------------------------
// This file was automatically generated by J2CS Translator (http://j2cstranslator.sourceforge.net/). 
// Version 1.3.6.20101221_01     
// 1/4/11 10:24 AM    
// ${CustomMessageForDisclaimer}                                                                             
// --------------------------------------------------------------------------------------------------
namespace ILOG.J2CsMapping.IO
{
	
	using ILOG.J2CsMapping.IO;
	using System;
	using System.Collections;
	using System.Collections.Generic;
	using System.ComponentModel;
	using System.IO;
	using System.Runtime.CompilerServices;
	
	/// <summary>
	/// PushbackInputStream is a filter class which allows bytes read to be pushed
	/// back into the stream so that they can be reread. Parsers may find this
	/// useful. There is a progammable limit to the number of bytes which may be
	/// pushed back. If the buffer of pushed back bytes is empty, bytes are read from
	/// the source input stream.
	/// </summary>
	///
	public class PushbackInputStream : FilterInputStream {
		/// <summary>
		/// The <c>byte</c> array containing the bytes to read.
		/// </summary>
		///
		protected internal byte[] buf;
	
		/// <summary>
		/// The current position within the byte array <c>buf</c>. A value
		/// equal to buf.length indicates no bytes available. A value of 0 indicates
		/// the buffer is full.
		/// </summary>
		///
		protected internal int pos;
	
		/// <summary>
		/// Constructs a new PushbackInputStream on the InputStream <c>in</c>.
		/// The size of the pushback buffer is set to the default, or 1 byte.
		/// </summary>
		///
		/// <param name="in">the InputStream to allow pushback operations on.</param>
		public PushbackInputStream(Stream ins0) : base(ins0) {
			buf = (ins0 == null) ? null : new byte[1];
			pos = 1;
		}
	
		/// <summary>
		/// Constructs a new PushbackInputStream on the InputStream <c>in</c>.
		/// The size of the pushback buffer is set to <c>size</c>.
		/// </summary>
		///
		/// <param name="in">the InputStream to allow pushback operations on.</param>
		/// <param name="size">the size of the pushback buffer (<c>size>=0</c>).</param>
		public PushbackInputStream(Stream ins0, int size) : base(ins0) {
			if (size <= 0) {
				throw new ArgumentException("K0058"); //$NON-NLS-1$
			}
			buf = (ins0 == null) ? null : new byte[size];
			pos = size;
		}
	
		/// <summary>
		/// Answers a int representing then number of bytes that are available before
		/// this PushbackInputStream will block. This method returns the number of
		/// bytes available in the pushback buffer plus those available in the target
		/// stream.
		/// </summary>
		///
		/// <returns>int the number of bytes available before blocking.</returns>
		/// <exception cref="System.IO.IOException">If an error occurs in this stream.</exception>
        public virtual int Available()
        {
            throw new NotImplementedException("Available");
            /*
			if (buf == null) {
				throw new IOException();
			}
			return buf.Length - pos + ins0.Available();*/
		}
	
		/// <summary>
		/// Close this PushbackInputStream. This implementation closes the target
		/// stream.
		/// </summary>
		///
		/// <exception cref="IOException">If an error occurs attempting to close this stream.</exception>
		public override void Close() {
			if (ins0 != null) {
				ins0.Close();
				ins0 = null;
				buf = null;
			}
		}
	
		/// <summary>
		/// Answers a boolean indicating whether or not this PushbackInputStream
		/// supports mark() and reset(). This implementation always answers false
		/// since PushbackInputStreams do not support mark/reset.
		/// </summary>
		///
		/// <returns>boolean indicates whether or not mark() and reset() are
		/// supported.</returns>
		public override bool MarkSupported() {
			return false;
		}
	
		/// <summary>
		/// Reads a single byte from this PushbackInputStream and returns the result
		/// as an int. The low-order byte is returned or -1 of the end of stream was
		/// encountered. If the pushback buffer does not contain any available bytes
		/// then a byte from the target input stream is returned.
		/// </summary>
		///
		/// <returns>int The byte read or -1 if end of stream.</returns>
		/// <exception cref="IOException">If an IOException occurs.</exception>
		public override int ReadByte() {
			if (buf == null) {
				throw new IOException();
			}
			// Is there a pushback byte available?
			if (pos < buf.Length) {
				return (buf[pos++] & 0xFF);
			}
			// Assume read() in the InputStream will return low-order byte or -1
			// if end of stream.
			return ins0.ReadByte();
		}
	
		/// <summary>
		/// Reads at most <c>length</c> bytes from this PushbackInputStream
		/// and stores them in byte array <c>buffer</c> starting at
		/// <c>offset</c>. Answer the number of bytes actually read or -1 if
		/// no bytes were read and end of stream was encountered. This implementation
		/// reads bytes from the pushback buffer first, then the target stream if
		/// more bytes are required to satisfy <c>count</c>.
		/// </summary>
		///
		/// <param name="buffer">the byte array in which to store the read bytes.</param>
		/// <param name="offset">the offset in <c>buffer</c> to store the read bytes.</param>
		/// <param name="length">the maximum number of bytes to store in <c>buffer</c>.</param>
		/// <returns>the number of bytes actually read or -1 if end of stream.</returns>
		/// <exception cref="IOException">If an IOException occurs.</exception>
		public override int Read(byte[] buffer, int offset, int length) {
			if (buf == null) {
				throw new IOException();
			}
			if (buffer == null) {
				throw new NullReferenceException();
			}
			// avoid int overflow
			if (offset < 0 || offset > buffer.Length || length < 0
					|| length > buffer.Length - offset) {
				throw new IndexOutOfRangeException();
			}
	
			int copiedBytes = 0, copyLength = 0, newOffset = offset;
			// Are there pushback bytes available?
			if (pos < buf.Length) {
				copyLength = (buf.Length - pos >= length) ? length : buf.Length
						- pos;
				System.Array.Copy((Array)(buf),pos,(Array)(buffer),newOffset,copyLength);
				newOffset += copyLength;
				copiedBytes += copyLength;
				// Use up the bytes in the local buffer
				pos += copyLength;
			}
			// Have we copied enough?
			if (copyLength == length) {
				return length;
			}
			int inCopied = ins0.Read(buffer, newOffset, length - copiedBytes);
			if (inCopied > 0) {
				return inCopied + copiedBytes;
			}
			if (copiedBytes == 0) {
				return inCopied;
			}
			return copiedBytes;
		}
	
		/// <summary>
		/// Skips <c>count</c> number of bytes in this PushbackInputStream.
		/// Subsequent <c>read()</c>'s will not return these bytes unless
		/// <c>reset()</c> is used. This implementation skips
		/// <c>count</c> number of bytes in the buffer and/or the target
		/// stream.
		/// </summary>
		///
		/// <param name="count">the number of bytes to skip.</param>
		/// <returns>the number of bytes actually skipped.</returns>
		/// <exception cref="IOException">If the stream is already closed or another IOExceptionoccurs.</exception>
        public override long Skip(long count)
        {
			if (ins0 == null) {
				throw new IOException("K0059"); //$NON-NLS-1$
			}
			if (count <= 0) {
				return 0;
			}
			long numSkipped = 0;
			if (pos < buf.Length) {
				numSkipped += (count < buf.Length - pos) ? (long) (count) : (long) (buf.Length - pos);
				pos += (int) numSkipped;
			}
			if (numSkipped < count) {
                numSkipped += ins0.Seek(count - numSkipped, SeekOrigin.Current);
				// numSkipped += ins0.Skip(count - numSkipped);
			}
			return numSkipped;
		}
	
		/// <summary>
		/// Push back all the bytes in <c>buffer</c>. The bytes are pushed
		/// so that they would be read back buffer[0], buffer[1], etc. If the push
		/// back buffer cannot handle the entire contents of <c>buffer</c>,
		/// an IOException will be thrown. Some of the buffer may already be in the
		/// buffer after the exception is thrown.
		/// </summary>
		///
		/// <param name="buffer">the byte array containing bytes to push back into the stream.</param>
		/// <exception cref="IOException">If the pushback buffer becomes, or is, full.</exception>
		public void Unread(byte[] buffer) {
			Unread(buffer, 0, buffer.Length);
		}
	
		/// <summary>
		/// Push back <c>length</c> number of bytes in <c>buffer</c>
		/// starting at <c>offset</c>. The bytes are pushed so that they
		/// would be read back buffer[offset], buffer[offset+1], etc. If the push
		/// back buffer cannot handle the bytes copied from <c>buffer</c>,
		/// an IOException will be thrown. Some of the bytes may already be in the
		/// buffer after the exception is thrown.
		/// </summary>
		///
		/// <param name="buffer">the byte array containing bytes to push back into the stream.</param>
		/// <param name="offset">the location to start taking bytes to push back.</param>
		/// <param name="length">the number of bytes to push back.</param>
		/// <exception cref="IOException">If the pushback buffer becomes, or is, full.</exception>
		public void Unread(byte[] buffer, int offset, int length) {
			if (length > pos) {
				// Pushback buffer full
				throw new IOException("K007e"); //$NON-NLS-1$
			}
			// avoid int overflow
			if (offset < 0 || offset > buffer.Length || length < 0
					|| length > buffer.Length - offset) {
				throw new IndexOutOfRangeException();
			}
	
			for (int i = offset + length - 1; i >= offset; i--) {
				Unread(buffer[i]);
			}
		}
	
		/// <summary>
		/// Push back one <c>byte</c>. Takes the byte <c>oneByte</c>
		/// and puts in in the local buffer of bytes to read back before accessing
		/// the target input stream.
		/// </summary>
		///
		/// <param name="oneByte">the byte to push back into the stream.</param>
		/// <exception cref="IOException">If the pushback buffer is already full.</exception>
		public void Unread(int oneByte) {
			if (buf == null) {
				throw new IOException();
			}
			if (pos == 0) {
				throw new IOException("K007e"); //$NON-NLS-1$
			}
			buf[--pos] = (byte) oneByte;
		}
	
		/// <summary>
		/// Make a mark of the current position in the stream but the mark method
		/// does nothing.
		/// </summary>
		///
		/// <param name="readlimit">the maximum number of bytes that are able to be read beforethe mark becomes invalid</param>
		/// <seealso cref="M:ILOG.J2CsMapping.IO.IlFilterInputStream.Mark(System.Int32)"/>
        public override void Mark(int readlimit)
        {
			return;
		}
	
		/// <summary>
		/// Reset current position to the mark made previously int the stream, but
		/// the reset method will throw IOException and do nothing else if called.
		/// </summary>
		///
		/// <exception cref="IOException">If the method is called</exception>
		/// <seealso cref="M:ILOG.J2CsMapping.IO.IlFilterInputStream.Reset"/>
        public override void Reset()
        {
			throw new IOException();
		}
	}
}
